package com.example.chess.game;

import com.example.chess.ChessApplication;
import com.example.chess.mapper.UserMapper;
import com.example.chess.model.User;
import com.example.chess.util.GameRequest;
import com.example.chess.util.GameResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 一个游戏房间
 */
@Data
public class Room {
    private String roomId;
    private User user1;
    private User user2;
    private ObjectMapper objectMapper = new ObjectMapper();
    private int whiteUser;// 先手
    private int[][] board = new int[15][15];// 初始化棋盘    --     判断胜负
    // 1 玩家一   2 玩家二

    // 观战列表
    ConcurrentHashMap<Integer, WebSocketSession> watches = new ConcurrentHashMap<>();

    private OnlineUserManager onlineUserManager;

    private RoomManager roomManager;

    private UserMapper userMapper;

    public Room(){
        // 生成一个唯一的字符串构成房间号
        this.onlineUserManager = ChessApplication.ac.getBean(OnlineUserManager.class);
        this.roomManager = ChessApplication.ac.getBean(RoomManager.class);
        this.userMapper = ChessApplication.ac.getBean(UserMapper.class);
        this.roomId = UUID.randomUUID().toString();
    }

    // 进入观战队列
    public void enterWatch(Integer userId, WebSocketSession session){
        watches.put(userId, session);
    }

    // 出队列
    public void outWatch(Integer userId){
        watches.remove(userId);
    }

    public void putChess(String payload) throws IOException {
        GameRequest request = objectMapper.readValue(payload, GameRequest.class);
        int chess = request.getUserId();
        int row = request.getRow();
        int col = request.getCol();
        if (board[row][col] != 0){
            // 当前位置已经有子了
            System.out.println("当前位置 (" + row + ", " + col +  ") 已经有子了");
            return;
        }
        // 落子
        board[row][col] = chess;
        // 打印棋盘信息
        printBoard();

        // 胜负判定
        int winner = checkWinner(row, col, chess);

        // 响应
        GameResponse response = new GameResponse();
        response.setMessage("putChess");
        response.setUserId(request.getUserId());
        response.setRow(row);
        response.setCol(col);
        response.setWinner(winner);

        // 返回响应 --- 给房间里的所有客户端返回
        WebSocketSession session1 = onlineUserManager.getRoomSession(user1.getUserId());// 得到玩家一的会话
        WebSocketSession session2 = onlineUserManager.getRoomSession(user2.getUserId());// 得到玩家二的会话

        if (session1 == null){
            // 玩家一下线    ---     玩家二获胜
            System.out.println("玩家一掉线");
            response.setReason("dropped");
            response.setWinner(user2.getUserId());
        }
        if (session2 == null){
            // 玩家一下线    ---     玩家二获胜
            System.out.println("玩家二掉线");
            response.setReason("dropped");
            response.setWinner(user1.getUserId());
        }
        if (session1 != null){
            session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
        if (session2 != null){
            session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
        // 给所有的观战的人返回
        Collection<WebSocketSession> watchSessions = watches.values();
        for (WebSocketSession session : watchSessions) {
            if (session != null && session.isOpen()){
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            }
        }

        // 如果胜负已分   ---     销毁房间
        if (winner != 0){
            System.out.println("当前游戏胜负已分, 获胜方为：" + winner);
            // 修改积分
            int winId = winner;
            int loseId = winner == user1.getUserId() ? user2.getUserId() : user1.getUserId();
            userMapper.win(winId);
            userMapper.lose(loseId);
            roomManager.remove(roomId, user1.getUserId(), user2.getUserId());
        }
    }

    private void printBoard() {
        System.out.println("===================打印棋盘信息(" + roomId +  ")==================");
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                System.out.print(board[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println("===================打印棋盘信息(" + roomId +  ")==================");
    }

    // 胜负判断       玩家一胜利 --> 1  玩家二胜利 --> 2     无人胜利 --> 0
    //                      当前落子行列          当前落子的类型
    private int checkWinner(int row, int col, int chess) {
        // 行
        int sum = 1;// 本身的一颗棋子, 加上周围的
        int left = col-1, right = col+1;
        while (left >= 0 && board[row][left] == chess){
            sum++;
            left--;
        }
        while (right < 15 && board[row][right] == chess){
            sum++;
            right++;
        }
        if (sum >= 5) return chess;

        // 列
        sum = 1;// 本身的一颗棋子, 加上周围的
        int top = row-1, bottom = row+1;
        while (top >= 0 && board[top][col] == chess){
            sum++;
            top--;
        }
        while (bottom < 15 && board[bottom][col] == chess){
            sum++;
            bottom++;
        }
        if (sum >= 5) return chess;

        // 正对角线
        sum = 1;// 本身的一颗棋子, 加上周围的
        int x1 = row-1, y1=col-1, x2=row+1, y2=col+1;
        while (x1 >= 0 && y1 >= 0 && board[x1][y1] == chess){
            sum++;
            x1--;
            y1--;
        }
        while (x2 < 15 && y2 < 15 && board[x2][y2] == chess){
            sum++;
            x2++;
            y2++;
        }
        if (sum >= 5) return chess;

        // 副对角线
        sum = 1;// 本身的一颗棋子, 加上周围的
        x1 = row+1;
        y1=col-1;
        x2=row-1;
        y2=col+1;
        while (x1<15 && y1>=0 && board[x1][y1] == chess){
            sum++;
            x1++;
            y1--;
        }
        while (x2>=0 && y2<15 && board[x2][y2] == chess){
            sum++;
            x2--;
            y2++;
        }
        if (sum >= 5) return chess;

        return 0;
    }
}
